function getObj(s) {
  for (var i in s) {
    if (typeof s[i] == "object") {
      f(s[i]);
    } else {
      console.log(s[i]);
    }
  }
}
//声明一个指令解析类
const complierUtil = {
  //获取对应的值
  getVal(expr, vm) {
    let expArr = expr.split("."); //person.name  vm.$data[person][name]
    return expArr.reduce((data, currentVal) => {
      return data[currentVal]
    }, vm.$data);
  },
  setVal(expr, vm, inputVal) {
    let expArr = expr.split(".");
    return expArr.reduce((data, currentVal,index) => {
      // data[currentVal] = inputVal
      if(index===expArr.length-1){
        console.log('index',data)
        data[currentVal] = inputVal
      }else{
        return data[currentVal]
      }
    }, vm.$data);
  },
  getContentVal(expr, vm) {
    console.log("1111111：", expr);
    return expr.replace(/\{\{(.+?)\}\}/g, (...args) => {
      return this.getVal(args[1], vm);
    });
  },
  //文本
  text(node, vm, expr) {
    let value;
    if (expr.indexOf("{{") != -1) {
      value = expr.replace(/\{\{(.+?)\}\}/g, (...args) => {
        //注意，watch里面调用的getVal的方法
        new watcher(vm, args[1], () => {
          this.updater.textUpdater(node, this.getContentVal(expr, vm));
        });
        return this.getVal(args[1], vm);
      });
    } else {
      new watcher(vm, expr, (newVal) => {
        this.updater.textUpdater(node, newVal);
      });
      value = this.getVal(expr, vm);
    }

    this.updater.textUpdater(node, value);
  },
  html(node, vm, expr) {
    const value = this.getVal(expr, vm);
    //关键点（6）,实例化watcher
    new watcher(vm, expr, (newVal) => {
      this.updater.htmlUpdater(node, newVal);
    });
    this.updater.htmlUpdater(node, value);
  },
  model(node, vm, expr) {
    const value = this.getVal(expr, vm);
    new watcher(vm, expr, (newVal) => {
      this.updater.modelUpdater(node, newVal);
    });
    //视图-数据-视图
    node.addEventListener(
      "input",
      (e) => {
        this.setVal(expr, vm, e.target.value);
      },
      false
    );
    this.updater.modelUpdater(node, value);
  },
  bind(node, vm, type, expr) {
    const value = this.getVal(expr, vm);
    new watcher(vm, expr, (newVal) => {
      node.setAttribute(type, newVal);
    });
    node.setAttribute(type, value);
  },
  on(node, vm, type, expr) {
    const fn = vm.options.methods[expr];
    node.addEventListener(type, fn.bind(vm), false);
  },
  //更新装置
  updater: {
    textUpdater(node, value) {
      node.textContent = value;
    },
    htmlUpdater(node, value) {
      node.innerHTML = value;
    },
    modelUpdater(node, value) {
      node.value = value;
    },
  },
};
//创建watcher监听器
class watcher {
  constructor(vm, expr, callback) {
    this.vm = vm;
    this.expr = expr;
    this.callback = callback;
    this.oldVal = this.getOldVal(); //保存旧值跟新值做对比使用
  }
  getOldVal() {
    //(关键点4)
    Dep.target = this;
    //获取旧值
    const oldVal = complierUtil.getVal(this.expr, this.vm);
    //(关键点5)
    Dep.target = null;
    return oldVal;
  }
  updater() {
    //更新新值
    const newVal = complierUtil.getVal(this.expr, this.vm);
    if (newVal !== this.oldVal) {
      //执行callBack返回新值
      this.callback(newVal);
    }
  }
}
//创建dep收集器
class Dep {
  constructor() {
    //定义一个空数组，收集watcher
    this.depArr = [];
  }
  addDep(watcher) {
    //watcher添加到数组中的方法
    this.depArr.push(watcher);
  }
  notify() {
    // console.log("1111111111");
    //遍历整个收集器，通知对应的watcher做更新
    this.depArr.forEach((watch) => {
      //调用watch的更新函数
      watch.updater();
    });
  }
}
// 数据劫持
class Observer {
  constructor(data, vm) {
    this.data = data;
    this.$vm = vm;
    //劫持数据的方法
    this.observe(data);
  }
  observe(data) {
    if (data && Object.prototype.toString.call(data) === "[object Object]") {
      Object.keys(data).forEach((key) => {
        // console.log("key值：", key);
        //给每个属性绑定对应的get和set方法
        this.defineReactive(data, key, data[key]);
      });
    }
  }
  defineReactive(data, key, value) {
    var that = this; //解决this指向问题
    //数据层及递归处理
    this.observe(value);
    let dep = new Dep();
    //利用Object.defineProperty做数据的劫持，给每个属性添加get和set方法
    Object.defineProperty(data, key, {
      enumerable: true, //是否可遍历
      configurable: false, //是否可编辑
      get() {
        //数据初始化,添加到dep收集器(关键点1-observer与dep建立联系)
        Dep.target && dep.addDep(Dep.target); //（关键点2-watcher如何传递进去建立联系）
        return value;
      },
      set(newVal) {
        //给新值做对应的监听
        that.observe(newVal);
        if (newVal !== value) {
          //更新值
          value = newVal;
        }
        //进去dep，通知watcher进入更新（关键点3）
        dep.notify();
      },
    });
  }
}
//vue模板解析器
class complier {
  constructor(el, vm) {
    // el有可能是元素节点，也可能是id名。所以要做判断isElement
    this.el = this.isElement(el) ? el : document.querySelector(el);
    this.$vm = vm;
    //获取文档碎片，减少重绘和回流
    const fragment = this.nodeFragment(this.el);

    // 编译文档碎片
    this.complies(fragment);

    // 将获得的文档碎片加入到根元素上
    this.el.appendChild(fragment);
  }
  complies(ele) {
    // 获取所有子节点（伪数组）
    const childNodes = ele.childNodes;

    Array.from(childNodes).forEach((node) => {
      //node需要判断是元素节点还是文本节点
      if (this.isElement(node)) {
        //获取元素节点的所有属性（伪数组）
        const attrs = node.attributes;
        Array.from(attrs).forEach((attr) => {
          const { name, value } = attr;
          //判断是否是以v-开头
          if (this.isDirective(name) === "v-") {
            //从-第二个开始截取
            const [, instruction] = name.split("-");
            const [type, directive] = instruction.split(":");
            if (directive) {
              complierUtil[type] &&
                complierUtil[type](node, this.$vm, directive, value);
            } else {
              complierUtil[instruction] &&
                complierUtil[instruction](node, this.$vm, value);
            }
            node.removeAttribute("v-" + instruction);
          } else if (this.isDirective(name) === "@") {
            const type = name.substr(1);
            complierUtil["on"](node, this.$vm, type, value);
            node.removeAttribute("@" + type);
          }
        });
      } else {
        //文本节点编译
        if (this.isInterpolation(node)) {
          complierUtil.text(node, this.$vm, node.textContent);
        }
      }
      //有ul>li这种情况，采用递归解决
      this.complies(node);
    });
  }
  //判断是否为{{}}这种情况
  isInterpolation(node) {
    return /\{\{(.*)\}\}/.test(node.textContent);
  }
  //判断指令
  isDirective(attrName) {
    if (attrName.indexOf("v-") == 0) {
      return "v-";
    } else if (attrName.indexOf("@") == 0) {
      return "@";
    }
  }

  //获取文档碎片函数
  nodeFragment(el) {
    // 虚拟的节点对象
    const virDom = document.createDocumentFragment();
    let firstChild;
    while ((firstChild = el.firstChild)) {
      virDom.appendChild(firstChild);
    }
    return virDom;
  }
  isElement(node) {
    return node.nodeType === 1;
  }
}

class gVue {
  constructor(options) {
    this.$el = options.el;
    this.$data = options.data;
    this.options = options;
    //判断el是否存在，存在就开始complier解析
    if (this.$el) {
      //劫持所有数据
      new Observer(this.$data, this);
      // 实现一个解析器
      new complier(this.$el, this);
    }
  }
}
